package com.link2room.ironhide.util.image;

import com.link2room.common.constant.BaseConstant;
import com.link2room.common.constant.DefaultValue;
import com.link2room.common.enums.BaseSysExceptionEnum;
import com.link2room.common.exception.SysException;
import com.link2room.common.redis.RedisUtil;
import com.link2room.common.service.ILink2RoomApiBaseService;
import com.link2room.common.util.StringUtil;
import com.link2room.common.util.SysoptionUtil;
import com.link2room.enums.exception.IronhideSysExceptionEnum;
import com.link2room.ironhide.dto.result.base.L2RImgSourceDto;
import com.link2room.ironhide.exception.IronhideException;

import net.coobird.thumbnailator.Thumbnails;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;

/**
 * 图片工具
 * Created by LN on 2016/11/29.
 */
@Component("imageUtil")
public class ImageUtil {
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private ILink2RoomApiBaseService link2RoomApiBaseService;

    /**
     * 图片保存路径
     */
    private static final String SYS_PIC_URI_OPT = "img_uri_opt";
    /**
     * 图片访问域名
     */
    private static final String SYS_IMG_HOST = "img_host";


    private static class _ImgFileHead {
        public static final String JPEG = "FFD8FF"; // JPEG (jpg)
        public static final String PNG = "89504E47"; // PNG (png)
        public static final String GIF = "47494638"; // GIF  (gif)
    }


    /**
     * 文件后缀
     */
    private static final String IMG_POSTFIX = ".jpg";

    private static int[] widthsizes = {
            _WidthSize.IMG_SIZE_SRC,
            _WidthSize.IMG_SIZE_640,
            _WidthSize.IMG_SIZE_620,
            _WidthSize.IMG_SIZE_360,
            _WidthSize.IMG_SIZE_310,
            _WidthSize.IMG_SIZE_160,
            _WidthSize.IMG_SIZE_120,
            _WidthSize.IMG_SIZE_80
    };

    private static class _WidthSize {

        public static final int IMG_SIZE_SRC = 0;
        public static final int IMG_SIZE_640 = 640;
        public static final int IMG_SIZE_620 = 620;
        public static final int IMG_SIZE_360 = 360;
        public static final int IMG_SIZE_310 = 310;
        public static final int IMG_SIZE_160 = 160;
        public static final int IMG_SIZE_120 = 120;
        public static final int IMG_SIZE_80 = 80;

    }


    /**
     * 缓存时间
     */
    private final long expireTime = 60 * 60;

    public boolean isSamePic(ImgCompress img1, ImgCompress img2) throws IOException, NoSuchAlgorithmException {
        if (img1 != null && img2 != null) {
            return img1.getImageFileHashCode().equals(img2);
        } else {
            return false;
        }
    }

    /**
     * 缓存图片
     *
     * @param img
     * @throws IOException
     * @throws NoSuchAlgorithmException
     */
    public String cacheImg(ImgCompress img) throws IOException, NoSuchAlgorithmException {
        if (img == null) {
            return "";
        }
        String key = getKey(img);
        if (redisUtil.exists(key)) {
            //存在刷新时间
            redisUtil.expire(key, expireTime);
            return key;
        } else {
            redisUtil.set(key, img, expireTime);
            return key;
        }
    }

    private String getKey(ImgCompress img) throws IOException, NoSuchAlgorithmException {
        return BaseConstant.RedisConstant.TITLE.IMAGE + img.getImageFileHashCode();
    }

    /**
     * 获取图片
     */
    public ImgCompress getImages(String imageId) {
        if (redisUtil.exists(imageId)) {
            return (ImgCompress) redisUtil.get(imageId);
        } else {
            return null;
        }
    }

    /**
     * 检测图片文件是否合法
     *
     * @param file
     */
    public static void checkImageFile(MultipartFile file) throws IOException {
        if (file == null) {
            throw new SysException(BaseSysExceptionEnum.INVALID_PARA.getCode(),
                    BaseSysExceptionEnum.INVALID_PARA.getMsg() + "文件为空",
                    BaseSysExceptionEnum.INVALID_PARA.getBizType());
        }
        if (file.getSize() <= 0) {
            throw new SysException(BaseSysExceptionEnum.INVALID_PARA.getCode(),
                    BaseSysExceptionEnum.INVALID_PARA.getMsg() + "文件大小不合法",
                    BaseSysExceptionEnum.INVALID_PARA.getBizType());
        }
        String fileName = file.getName();

        if (isNotImage(file)) {
            throw new SysException(BaseSysExceptionEnum.INVALID_PARA.getCode(),
                    BaseSysExceptionEnum.INVALID_PARA.getMsg() + "文件名不合法",
                    BaseSysExceptionEnum.INVALID_PARA.getBizType());
        }
    }

    private static boolean isNotImage(MultipartFile file) throws IOException {
        InputStream is = file.getInputStream();
        byte[] b = new byte[3];
        is.read(b, 0, b.length);
        String fileHead = bytesToHexString(b).toLowerCase();
        if (fileHead.startsWith(_ImgFileHead.GIF) ||
                fileHead.startsWith(_ImgFileHead.JPEG) ||
                fileHead.startsWith(_ImgFileHead.PNG)) {
            return true;
        } else {
            return false;
        }
    }

    private static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * 图片持久化
     *
     * @param dto
     * @return 相对路径
     */
    public Img imgePersistence(String lhotelGroupCode, String lhotelCode, L2RImgSourceDto dto) throws Exception {
        return localPersistence(lhotelGroupCode, lhotelCode, dto);
    }

    public static class Img {
        private String relativePath;
        private String fileCode;

        public String getFileCode() {
            return fileCode;
        }

        public void setFileCode(String fileCode) {
            this.fileCode = fileCode;
        }

        public String getRelativePath() {
            return relativePath;
        }

        public void setRelativePath(String relativePath) {
            this.relativePath = relativePath;
        }
    }

    /**
     * 本地持久化
     *
     * @param dto
     * @return RelativePath 文件保存相对路径
     */
    private Img localPersistence(String lhotelGroupCode, String lhotelCode, L2RImgSourceDto dto) throws Exception {
        if (dto == null) {
            return null;
        }
        ImgCompress img = dto.getImgCompress();
        if (img == null) {
            return null;
        }
        if (StringUtil.isBlank(lhotelGroupCode)) {
            lhotelGroupCode = DefaultValue.LHOTEL_GROUP_CODE;
        }
        if (StringUtil.isBlank(lhotelCode)) {
            lhotelCode = DefaultValue.LHOTEL_CODE;
        }
        //查询图片保存路径
        String uriStr = SysoptionUtil.getSysOption(lhotelGroupCode, null, SYS_PIC_URI_OPT);
        String root = uriStr;
        if (StringUtil.isBlank(root)) {
            throw new IronhideException(IronhideSysExceptionEnum.IMG_URI_OPT.getCode(),
                    IronhideSysExceptionEnum.IMG_URI_OPT.getMsg() + "item is " + SYS_PIC_URI_OPT,
                    IronhideSysExceptionEnum.IMG_URI_OPT.getBizType());
        }
        Img imgDto = new Img();
        String fileCode = "";
        String fileRelativePath = "";
        String relativePath = getDirRelativePath(lhotelGroupCode, lhotelCode);
        String dir = getImgDir(root, relativePath);
        String srcFileName = createFileName("", _WidthSize.IMG_SIZE_SRC);
        ;
        //生成并保存所有size的图片
        for (int size : widthsizes) {
            String fileName;
            if (size == _WidthSize.IMG_SIZE_SRC) {
                fileName = srcFileName;
                fileRelativePath = fileRelativePath(relativePath, fileName);
            } else {
                fileName = createFileName(srcFileName, size);
            }

            saveImage(img, dir, fileName, size);
        }
        fileCode = createFileCode();
        imgDto.setRelativePath(fileRelativePath);
        imgDto.setFileCode(fileCode);
        return imgDto;
    }

    private String createFileCode() {
        UUID uuuid = UUID.randomUUID();
        return uuuid.toString() + System.currentTimeMillis();
    }

    private void saveImage(ImgCompress ic, String dir, String fileName, int widthSize) throws IOException {
        if (widthSize == _WidthSize.IMG_SIZE_SRC) {
            Thumbnails.of(ic.getImg())
                    .scale(1)
                    .toFile(filePath(dir, fileName));
        } else {
            Thumbnails.of(ic.getImg())
                    .width(widthSize)
                    .height(newHieght(ic, widthSize))
                    .toFile(filePath(dir, fileName));
        }
    }


    private String filePath(String dir, String fileName) {
        return dir + "/" + fileName;
    }

    /**
     * 文件保存相对路径
     *
     * @param relativePath
     * @param fileName
     * @return
     */
    private String fileRelativePath(String relativePath, String fileName) {
        return relativePath + "/" + fileName;
    }

    private int newHieght(ImgCompress ic, int widthSize) {
        int rate = ic.getWidth() / widthSize;
        if (rate == 0) {
            return ic.getHeight();
        } else {
            return ic.getHeight() / rate;
        }
    }

    /**
     * 生成文件名
     *
     * @return
     */
    private String createFileName(String fileName, int size) {
        UUID uuuid = UUID.randomUUID();
        if (size == _WidthSize.IMG_SIZE_SRC) {
            return DefaultValue.MARK + uuuid.toString() + IMG_POSTFIX;
        } else {
            return fileName + DefaultValue.MARK + Integer.toString(size) + IMG_POSTFIX;
        }
    }

    private String getImgDir(String root, String relativePath) {
        String dir = root + relativePath;
        File file = new File(dir);
        if (file.exists()) {
            return dir;
        } else {
            file.mkdirs();
            return dir;
        }
    }

    /**
     * 相对路径
     *
     * @param lhotelGroupCode
     * @param lhotelCode
     * @return
     */
    private String getDirRelativePath(String lhotelGroupCode, String lhotelCode) {
        return "/" + lhotelGroupCode + "/" + lhotelCode;
    }

    /**
     * 查找图片host
     *
     * @param lhotelGroupCode
     * @return
     * @throws Exception
     */
    public String findImgHost(String lhotelGroupCode) throws Exception {
        return SysoptionUtil.getSysOption(lhotelGroupCode, null, SYS_IMG_HOST);
    }

}
